package com.demo.test.leak

import android.app.Activity
import android.os.Bundle
import android.os.SystemClock
import android.util.Log
import android.widget.TextView
import com.fortest.R
import com.demo.Tags

/**
泄露方式：非静态内部类默认持有外部类的引用——Thread
泄露原因：Activity开启了一个新线程执行任务，
这个任务是个“匿名内部类”，是Runnable的子类，是非静态内部类（包括匿名内部类），默认持有外部类（Activity）的引用，
新线程的生命周期比Activity长，
当Activity退出时，任务还没执行完，Runnable对象持有Activity，导致Activity泄露。

泄露报告　－－　StrictMode：
2020-05-24 20:02:02.832 3221-3221/com.example.myapplication E/StrictMode: class com.demo.test.leak.ActivityLeakI_Thread3; instances=2; limit=1
android.os.StrictMode$InstanceCountViolation: class com.demo.test.leak.ActivityLeakI_Thread3; instances=2; limit=1
at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

泄露报告　－－　LeakCanary：
98964 bytes retained by leaking objects
Displaying only 1 leak trace out of 3 with the same signature
Signature: 56f8e7485a62d885777d16b2dab6c6a4468fde36
┬───
│ GC Root: Local variable in native code
│
├─ java.lang.Thread instance
│    Leaking: UNKNOWN
│    Thread name: 'Thread-6'
│    ↓ Thread.target
│             ~~~~~~
├─ com.demo.test.leak.ActivityLeakI_Thread3$onCreate$1 instance
│    Leaking: UNKNOWN
│    Anonymous class implementing java.lang.Runnable
│    ↓ ActivityLeakI_Thread3$onCreate$1.this$0
│                                       ~~~~~~
╰→ com.demo.test.leak.ActivityLeakI_Thread3 instance
​     Leaking: YES (ObjectWatcher was watching this because com.demo.test.leak.ActivityLeakI_Thread3 received Activity#onDestroy() callback and Activity#mDestroyed is true)
​     key = 82e3fc5a-4753-4d12-a919-02a02e293df9
​     watchDurationMillis = 109078
 **/
class ActivityLeakI_Thread3 : Activity() {
    val TAG = Tags.leakThread3
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_leak_common)
        val textView = findViewById<TextView>(R.id.helper_text)
        textView.text = "泄露方式：非静态内部类默认持有外部类的引用——Thread\n" +
                "泄露原因：Activity开启了一个新线程执行任务，\n" +
                "这个任务是个“匿名内部类”，是Runnable的子类，是非静态内部类（包括匿名内部类），默认持有外部类（Activity）的引用，\n" +
                "新线程的生命周期比Activity长，\n" +
                "当Activity退出时，任务还没执行完，Runnable对象持有Activity，导致Activity泄露。"

        Thread(Runnable() {
            while (true) {
                Log.d(TAG, "do some thing")
                SystemClock.sleep(10000)
            }
        }).start()
    }


}
